/**
 * 接收用户消息接口
 */

 //websocket消息处理

//引入Q模块
var Q = require('q');
//引入公共函数
var util = require('../../util');
//引入crypto来进行sha1加密
var crypto = require('crypto');
//存放redis操作实例
var redis = null;
//存放mongodb操作实例
var db = null;
//存放配置变量
var config = null;

//getMsg入口函数
var index = function(getData, postData, _config, _redis, _db, wsServer) {
	var deferred = Q.defer();
	//存放redis操作实例
	redis = _redis;
	//存放db操作实例
	db = _db;
	//存放config变量
	config = _config;
	//判断是否存在signature、timestamp、nonce
	util.isSet(getData.signature, getData.timestamp, getData.nonce).then(function() {
		//检查消息是否来自微信服务器
		return checkSigntrue(getData.signature, config.msgToken, getData.timestamp, getData.nonce);
	}, function() {
		//接收微信消息参数不全
		deferred.reject('-0011');
	}).then(function() {
		//消息来自微信服务器
		console.log('数据来自微信服务器');
		if(getData.echostr) {
			deferred.resolve(['echo', getData.echostr]);
			return deferred.promise;
		}
		//检查是否为重复消息
		checkRepeatMsg(postData).then(function(repeat) {
			if(repeat) {
				//此次消息为重复消息
				console.log('发现重复的消息');
				//直接返回1
				deferred.resolve(1);
			}
			else {
				//此次消息未重复
				//获取商户ID
				getStoreData(postData).then(function(storeData) {
					//获取userId(openId)
					var userId = postData.FromUserName;
					//获取storeId
					var storeId = storeData.storeId;
					//获取桌号
					var tableNum = storeData.tableNum;
					//判断会话链是否失效
					if(!storeData.session) {
						console.log('此用户会话已失效');
						//发送失效消息给用户并返回1或错误码
						sendMsg(userId, config.sessionLoseMsg, postData.accessToken, config).then(function() {
							deferred.resolve(['echo', 'success']);
						}, function(errCode) {
							deferred.reject(errCode);
						});
					}
					else {
						var storeDB = {};
						//连接商户数据库
						db.connectDB(storeId).then(function(_db) {
							storeDB = _db
							//数据库查询商户的信息
							return storeDB.select('storeInfo');
						}, function() {
							//连接数据库失败
							deferred.reject('-0012');
						}).then(function(data) {
							//将结果转换成对象
							return util.array2obj(data);
						}, function() {
							//查询商户信息失败
							deferred.reject('-0040');
						}).then(function(storeInfo) {
							//获取在线客服个数
							getServiceSum(wsServer.clients, storeId).then(function(serviceSum) {
								console.log(storeInfo);
								//返回广播函数
								var broadcastDataFun = function(type, event, broadcastData) {
									broadcastData.userTableNum = tableNum;
									//返回broadcast类型用于广播
									deferred.resolve(['echo', 'success','broadcast', {
										storeId: storeId,
										type: type,
										event: event,
										data: broadcastData
									}]);
								};
								//判断是否为从客服按钮进入会话
								if(storeData.session == 'open') {
									//是从客服按钮进入的，先发送一条商户数据库中定义的
									//获取用户数据
									getUserData(userId).then(function(userData) {
										//判断是否存在此用户的数据
										if(userData) {
											//用户已注册过，发送一条商户自定义的欢迎语
											sendMsg(userId, storeInfo.storeWecome, postData.accessToken, config).then(function() {
												//向所有对应商户的客服发送此用户开启会话
												broadcastDataFun('user', 'openMsg', {
													userId: userId,
													userName: userData.userName,
													userGender: userData.userGender,
													userPhoto: userData.userPhoto,
													msgTimestamp: Date.now()
												});
											}, function(errCode) {
												//发送消息失败
												deferred.reject(errCode);
											});
										}
										else {
											//用户未注册过发送消息提示用户到小程序对应登录入口使用微信登录
											sendMsg(userId, config.noRegUserSessionMsg, postData.accessToken, config).then(function() {
												//发送消息成功
												deferred.resolve(1);
											}, function(errCode) {
												//发送消息失败
												deferred.reject(errCode);
											});
										}
									}, function(errCode) {
										//获取用户消息失败
										deferred.reject(errCode);
									});
								}
								else {
									//判断消息类型
									switch(postData.MsgType) {
										//文字消息
										case 'text':
											//文字消息处理函数
											textMsgHandler(storeDB, tableNum, userId, postData.Content, storeInfo, postData.accessToken, serviceSum).then(function(data) {
												//判断是否返回的需要广播的数据
												if(data) {
													//广播处理完毕的文字消息给对应商户的所有客服
													broadcastDataFun('user', 'sendMsg', data);
												}
												else {
													//未返回广播数据直接返回1不作处理
													deferred.resolve(1);
												}
											}, function(errCode) {
												//处理文字消息失败
												deferred.reject(errCode);
											});
										break;
										//图片消息
										case 'image':
											//图片消息处理函数
											imageMsgHandler(postData).then(function() {

											}, function() {

											});
										break;
										//事件消息
										case 'event':
											//事件消息处理
											switch(postData.Event) {
												case 'user_enter_tempsession':
													//由于此事件已经在上面在open中已经处理所以只返回1
													deferred.resolve(1);
												break;
											}
										break;
									}
								}
							}, function() {
								//获取客服个数失败
								deferred.reject('-0098');
							});
						}, function() {
							//将数据库信息转换为对象失败
							deferred.reject('-0041');
						});
					}
				//获取用户数据失败
				}, deferred.reject);
			}
		//检查是否重复消息失败
		}, deferred.reject);
	}, function() {
		console.log('错误，非来自微信服务器的消息');
		//接收到的微信消息非来自微信服务器
		deferred.reject('-0014');
	});
	return deferred.promise;
}

//消息来源验证函数
var checkSigntrue = function(signature, msgToken, timestamp, nonce) {
	var deferred = Q.defer();
	//将消息token和时间戳与随机值组成待排序的数组
	var sortData = [msgToken, timestamp, nonce];
	//将数组元素按字典顺序排序
	sortData.sort();
	//将数组元素使用空字符串连接起来
	var cryptData = sortData.join('');
	//使用crypto模块的sha1算法加密字符串
	var sha1 = crypto.createHash('sha1');
	//加入待加密字符串
	sha1.update(cryptData);
	//进行sha1加密
	cryptData = sha1.digest('hex');
	//判断是否与signature相同，如果相同则此消息证实来自微信服务器
	if(cryptData == signature) {
		//消息来自微信服务器
		deferred.resolve();
	}
	else {
		//错误，非来自微信服务器的消息
		deferred.reject();
	}
	return deferred.promise;
}

//获取对应商户的在线客服数量
var getServiceSum = function(clients, storeId) {
	var deferred = Q.defer();
	//尝试计数客服连接数量
	try {
		if(clients.size == 0) {
			deferred.resolve(0);
		}
		//客服总数变量
		var sum = 0;
		var index = 0;
		//遍历连接端
		clients.forEach(function(client) {
			//如果属于该商店的连接则为总数+1
			if(client.storeId == storeId) {
				sum++;
			}
			//判断是否执行完成
			if(++index == clients.size) {
				//返回总数
				deferred.resolve(sum);
			}
		});
	}
	catch(e) {
		//尝试失败直接返回0位客服在线
		deferred.resolve(0);
	}
	return deferred.promise;
}

//重复消息排重检查函数
var checkRepeatMsg = function(data) {
	var deferred = Q.defer();
	deferred.resolve(false);
	return deferred.promise;
}

//用户文字消息处理函数
var textMsgHandler = function(storeDB, tableNum, userId, content, storeInfo, accessToken, serviceSum) {
	var deferred = Q.defer();
	//检查消息中是否有预定义的自动回复列表中需要识别的关键字
	checkAutoReply(storeDB, content).then(function(replyContent) {
		var autoReply = false;
		//获取对应userId的用户数据
		getUserData(userId).then(function(userData) {
			//判断用户是否已注册
			if(userData) {
				storeDB.insert('chatListLogs', {
					sender: 'user',
					userId: userId,
					userName: userData.userName,
					userGender: userData.userGender,
					userPhoto: userData.userPhoto,
					userTableNum: tableNum,
					msg: content,
					autoReply: replyContent || '',
					timestamp: parseInt(Date.now()),
					serviceReceive: (serviceSum > 0 ? true : false)
				}).then(function() {
					console.log('存储用户发送的消息成功');
				}, function() {
					console.log('存储用户发送的消息失败', {
						userId: userId,
						userName: userData.userName,
						userGender: userData.userGender,
						userPhoto: userData.userPhoto,
						userTableNum: tableNum,
						msg: content,
						autoReply: replyContent || '',
						timestamp: parseInt(Date.now()),
						serviceReceive: (serviceSum > 0 ? true : false)
					});
				});
				if(replyContent) {
					console.log('系统已自动回复：' + replyContent);
					//指定已进行自动回复
					autoReply = replyContent;
					//消息中包含预定义关键字，发送关键字对应的预定义内容发送给用户
					sendMsg(userId, replyContent, accessToken, config).then(function() {}, function(errCode) {
						//发送消息失败
						deferred.reject(errCode);
					});
				}
				if(!replyContent && serviceSum == 0) {
					console.log('未找到客服');
					//发送客服未在线消息
					sendMsg(userId, storeInfo.storeServiceOffLineMsg, accessToken, config).then(function() {}, function(errCode) {
						deferred.reject(errCode);
					});
					deferred.resolve('success');
				}
				else {
					//用户已注册返回消息广播给对应商户的所有客服
					deferred.resolve({
						//用户ID
						userId: userId,
						//用户昵称
						userName: userData.userName,
						//用户性别
						userGender: userData.userGender,
						//用户头像
						userPhoto: userData.userPhoto,
						//用户桌号
						userTableNum: tableNum,
						//用户消息内容
						msgContent: content,
						//开启会话的时间戳
						msgTimestamp: parseInt(Date.now()),
						//是否已经进行自动回复
						autoReply: autoReply
					});
				}
			}
			else {
				//用户未注册发送让用户从小程序登录入口用微信登录后再发起会话的消息
				sendMsg(userId, config.noRegUserSessionMsg, accessToken, config).then(function() {
					//发送消息成功
					deferred.resolve();
				}, function(errCode) {
					//发送消息失败
					deferred.reject(errCode);
				});
			}
		}, function(errCode) {
			//获取用户数据失败
			deferred.reject(errCode);
		});
	}, function(errCode) {
		//检查是否可自动回复失败
		deferred.reject(errCode);
	});
	return deferred.promise;
}

//用户图片消息处理函数
var imageMsgHandler = function(data) {
	var deferred = Q.defer();

	return deferred.promise;
}

//检查是否可以进行自动回复函数
var checkAutoReply = function(storeDB, content) {
	var deferred = Q.defer();
	//读取商户数据库中的关键字回复表
	storeDB.select('autoReplyContents').then(function(autoReplyContents) {
		//判断关键字回复表是否为空
		if(autoReplyContents.length == 0) {
			//为空返回空
			deferred.resolve();
		}
		//遍历关键字回复表
		for(var index in autoReplyContents) {
			//将关键字与内容都转换为小写（indexOf对大小写敏感），检查内容是否包含关键字
			if(content.toLowerCase().indexOf(autoReplyContents[index].keyWord.toLowerCase()) != -1) {
				//包含关键字，返回关键字对应的预定义消息内容
				deferred.resolve(autoReplyContents[index].replyContent);
				break;
			}
			//判断是否已经遍历完毕
			if(index == autoReplyContents.length - 1) {
				//遍历完毕仍未找到对应的关键字则返回空
				deferred.resolve();
			}
		}
	}, function() {
		//mongodb查找自动回复列表失败
		deferred.reject('-0048');
	});
	return deferred.promise;
}

//获取storeId函数
var getStoreData = function(data) {
	var deferred = Q.defer();
	//得到用户的openId
	var userId = data.FromUserName;
	//判断是否是点击客服按钮进入聊天
	if(data.MsgType != 'event' || data.Event != 'user_enter_tempsession') {
		//是正常消息
		//读取redis中是否存在这样的消息会话链
		redis.get('msg:' + userId).then(function(storeDataStr) {
			if(storeDataStr) {
				util.isJson(storeDataStr).then(function(storeData) {
					//存在会话链取出storeId并返回session为msg类型
					deferred.resolve({
						session: 'msg',
						//商户id
						storeId: storeData.storeId,
						//商户桌号
						tableNum: storeData.tableNum
					});	
				}, function() {
					//会话链非法返回session关闭状态
					deferred.resolve({
						session: false
					});	
				});
			}
			else {
				//不存在会话链返回session关闭状态
				deferred.resolve({
					session: false
				});	
			}
		}, function() {
			//读取会话链失败
			deferred.reject('-0039');
		});
	}
	else {
		//是从按钮进入聊天界面的
		//获得传过来的storeId
		var storeData = data.SessionFrom;
		storeData = storeData.split('&');
		var storeId = storeData[0];
		var tableNum = storeData[1];
		//判断storeId和tableNum和userId是否存在
		util.isSet(storeId, tableNum, userId).then(function() {
			//设置客服会话，有有效期，超过有效期则会话失效
			redis.set('msg:' + userId, JSON.stringify({
				storeId: storeId,
				tableNum: tableNum
			})).then(function() {
				//设置会话有效期
				redis.expire('msg:' + userId, config.sessionExpire || 7200);
				//返回数据
				deferred.resolve({
					session: 'open',
					//商户id
					storeId: storeId,
					//商户桌号
					tableNum: tableNum,
				});	
			}, function() {
				//设置redis客服会话失败
				deferred.reject('-0038');
			});
		}, function() {
			//获取storeId和tableNum和userId失败
			deferred.reject('-0037');
		});
	}
	return deferred.promise;
}

//根据userId获取用户数据函数
var getUserData = function(userId) {
	var deferred = Q.defer();
	//连接到公共数据库common
	db.connectDB('common').then(function(commonDB) {
		//查询用户表
		return commonDB.select('users', {userId: userId});
	}, function() {
		//连接公共数据库失败
		deferred.reject('-0044');
	}).then(function(userData) {
		//判断是否存在该用户
		if(userData.length > 0) {
			//存在该用户返回用户数据
			deferred.resolve(userData[0]);
		}
		else {
			//不存在该用户返回空
			deferred.resolve();
		}
	}, function() {
		//查询公共数据库用户表失败
		deferred.reject('-0046');
	});
	return deferred.promise;
}

//发送消息给用户函数
var sendMsg = function(userId, content, accessToken, config) {
	var deferred = Q.defer();
	//发送POST请求到微信回复消息接口
	util.post('https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=' + accessToken, 'POST', {
		//发送给用户的用户openId
		touser: userId,
		//消息类型
		msgtype: 'text',
		//消息内容
		text: {
			content: content
		}
	}).then(function(data) {
		console.log('发送消息成功',data);
		if(data.errcode == 40001) {
			try {
				console.log('accessToken因特殊原因失效，重新获取');
				//发送GET请求到微信服务器取得accessToken数据
				util.get('https://api.weixin.qq.com/cgi-bin/token', {
					//小程序APPID
					appid: config.clientAppId,
					//小程序密钥APPSECRET
					secret: config.clientAppSecret,
					//指定请求类型
					grant_type: 'client_credential'
				}).then(function(jsonData) {
					//判断是否存在accessToken和accessToken有效期
					return util.isSet(jsonData.access_token, jsonData.expires_in);
				}, function() {
					//从微信服务器获取accessToken失败
					deferred.reject('-0016');
				}).then(function(jsonData) {
					//集合有效数据，jsonData来自isSet函数返回的参数列表
					let accessTokenData = {
						//accessToken值
						accessToken: jsonData[0],
						//得到当前时间戳（秒）
						timestamp: parseInt(Date.now() / 1000),
						//accessToken有效期
						expire: jsonData[1]
					};
					//存储accessToken到redis
					redis.set('accessToken', JSON.stringify(accessTokenData)).then(function() {
						//设置accessToken的生命周期（有效期，秒）
						return redis.expire('accessToken', accessTokenData.expire);
					}, function() {
						//存储accessToken到redis失败
						deferred.reject('-0023');
					}).then(function() {
						//存储accessToken成功，使用新的accessToken发送消息
						util.post('https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=' + accessTokenData.accessToken, 'POST', {
							//发送给用户的用户openId
							touser: userId,
							//消息类型
							msgtype: 'text',
							//消息内容
							text: {
								content: content
							}
						}).then(function(data) {
							console.log('发送消息成功',data);
							//消息发送成功
							deferred.resolve(data);
						}, function(err) {
							deferred.reject('-0041');
						});
					}, function() {
						//设置accessToken的生命周期失败
						deferred.reject('-0024');
					});
				}, function() {
					//从微信服务器获取的json数据中未找到accessToken
					deferred.reject('-0018');
				});
			}
			catch(e) {
				deferred.reject('-0041');
			}
		}
		else if(data.errcode != 0) {
			deferred.reject('-0041');
		}
		else {
			//消息发送成功
			deferred.resolve(data);
		}
	}, function(err) {
		console.log(err);
		deferred.reject('-0041');
	});
	return deferred.promise;
}

//暴露接口
module.exports = {
	index: index
};

/*util.isSet(data.MsgId).then(function() {
		redis.get(data.MsgId).then(function(msgMark) {
			if(msgMark && msgMark == data.FromUserName) {
				deferred.resolve(false);
			}
			else {
				redis.set(data.MsgId, data.FromUserName).then(function() {
					redis.expire(data.MsgId, 30);
					deferred.resolve(false);
				}, function() {
					deferred.reject('-0034');
				});
			}
		}, function() {
			deferred.reject('-0033');
		});
	}, function() {
		console.log('MSG为空',data.MsgId);
		deferred.reject('-0032');
		//deferred.resolve(false);
		//return util.isSet(data.FromUserName, data.CreateTime);
	});.then(function() {
		redis.get(data.FromUserName + data.CreateTime).then(function(msgMark) {
			if(msgMark) {
				console.log(data.MsgId);
				deferred.resolve(true);
			}
			else {
				redis.set(data.FromUserName + data.CreateTime, data.FromUserName).then(function() {
					redis.expire(data.FromUserName + data.CreateTime, 30);
					deferred.resolve(false);
				}, function() {
					deferred.reject('-0036');
				});
			}
		}, function() {
			deferred.reject('-0035');
		});*/
	//}, function() {
	//	deferred.reject('-0032');
	//});